﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Elevator.cs" company="">
//   
// </copyright>
// <summary>
//   The elevator.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

/* 
 * Author: Mikkel Thordal Andersen
 * Created: 17.11.2011
 */

namespace ITU_vs_Zombies.Scenery
{
    using System;
    using System.Diagnostics.Contracts;

    using ITU_vs_Zombies.Character;
    using ITU_vs_Zombies.Game;
    using ITU_vs_Zombies.Graphics;

    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;

    /// <summary>
    /// The elevator.
    /// </summary>
    [Serializable]
    public class Elevator : IGraphicsHelper
    {
        #region Constants and Fields

        /// <summary>
        /// The game time.
        /// </summary>
        [NonSerialized]
        public GameTime GameTime;

        /// <summary>
        /// The position.
        /// </summary>
        public Vector2 Position;

        /// <summary>
        /// The Speed.
        /// </summary>
        private const float Speed = 2.5f;

        /// <summary>
        /// The image.
        /// </summary>
        private readonly string image;

        /// <summary>
        /// The number of frames.
        /// </summary>
        private readonly uint numberOfFrames;

        /// <summary>
        /// The active.
        /// </summary>
        private bool active;

        /// <summary>
        /// The elevator texture.
        /// </summary>
        private Texture2D elevatorTexture;

        /// <summary>
        /// The player inside.
        /// </summary>
        private Player playerInside;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Elevator"/> class.
        /// </summary>
        /// <param name="image">
        /// The image.
        /// </param>
        /// <param name="numberOfFrames">
        /// The number of frames.
        /// </param>
        public Elevator(string image, uint numberOfFrames)
        {
            this.Animation = new Animation();
            this.numberOfFrames = numberOfFrames;
            this.IsGoingToFloor = 0;
            this.NumberFloor = 0;
            this.active = true;
            this.image = image;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets Animation.
        /// </summary>
        public Animation Animation { get; private set; }

        /// <summary>
        /// Gets Height.
        /// </summary>
        public float Height
        {
            get
            {
                return this.elevatorTexture.Height;
            }
        }

        /// <summary>
        /// Gets or sets IsGoingToFloor.
        /// </summary>
        public int IsGoingToFloor { get; set; }

        /// <summary>
        /// Gets or sets NumberFloor.
        /// </summary>
        public int NumberFloor { get; set; }

        /// <summary>
        /// Gets a value indicating whether Travelling.
        /// </summary>
        public bool Travelling
        {
            get
            {
                return this.IsGoingToFloor != this.NumberFloor;
            }
        }

        /// <summary>
        /// Gets Width.
        /// </summary>
        public float Width
        {
            get
            {
                return this.elevatorTexture.Width;
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets ActiveFloorWidth.
        /// </summary>
        private float ActiveFloorWidth
        {
            get
            {
                return Client.Floors.Find(f => f.Number == this.NumberFloor).Width;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// The draw.
        /// </summary>
        /// <param name="spriteBatch">
        /// The sprite batch.
        /// </param>
        public void Draw(SpriteBatch spriteBatch)
        {
            this.Animation.Draw(spriteBatch);
        }

        /// <summary>
        /// The go to floor.
        /// </summary>
        /// <param name="number">
        /// The number.
        /// </param>
        /// <param name="player">
        /// The player.
        /// </param>
        public void GoToFloor(int number, Player player)
        {
            Contract.Requires(number <= 5);

            if (!this.Travelling)
            {
                this.playerInside = player;

                this.IsGoingToFloor = number;
            }
        }

        /// <summary>
        /// The initialize.
        /// </summary>
        /// <param name="texture">
        /// The texture.
        /// </param>
        /// <param name="position">
        /// The position.
        /// </param>
        public void Initialize(Texture2D texture, Vector2 position)
        {
            this.elevatorTexture = texture;

            this.Position = position;

            this.active = true;
        }

        /// <summary>
        /// The load content.
        /// </summary>
        public void LoadContent()
        {
            this.elevatorTexture = Client.Content.Load<Texture2D>(this.image);

            this.Animation.Initialize(
                this.elevatorTexture, Vector2.Zero, (int)this.numberOfFrames, Color.White, 1f, true, false);
        }

        /// <summary>
        /// The update.
        /// </summary>
        /// <param name="gameTime">
        /// The game time.
        /// </param>
        /// <param name="position">
        /// The position.
        /// </param>
        public void Update(GameTime gameTime, Vector2 position)
        {
            this.Position.X = this.ActiveFloorWidth + position.X - this.Width;
            this.Move();
            this.Animation.Position = this.Position;
            this.Animation.Update(gameTime);
        }

        #endregion

        #region Methods

        /// <summary>
        /// The has arrived.
        /// </summary>
        private void HasArrived()
        {
            Client.Floors.Find(f => f.Number == this.NumberFloor).Active = false;
            Client.Floors.Find(f => f.Number == this.IsGoingToFloor).Players.Add(this.playerInside);
            Client.Floors.Find(f => f.Number == this.IsGoingToFloor).Active = true;
            this.playerInside.MovementEvent -= Client.Floors.Find(f => f.Number == this.NumberFloor).Move;
            Client.LoadDynamicContent();
            Client.Floors.Find(f => f.Number == this.NumberFloor).Players.Remove(this.playerInside);
            Client.Floors.Find(f => f.Number == this.NumberFloor).position.X = 0;
            Client.Floors.Find(f => f.Number == this.NumberFloor).Background.InitializePosition();
            this.playerInside.NumberFloor = this.IsGoingToFloor;
            this.playerInside.MovementEvent += Client.Floors.Find(f => f.Number == this.IsGoingToFloor).Move;
            this.NumberFloor = this.IsGoingToFloor;
            Client.Floors.Find(f => f.Number == this.NumberFloor).Visited = true;
            this.playerInside.Position = new Vector2(0, Player.StaticYPos);
        }

        /// <summary>
        /// The move.
        /// </summary>
        private void Move()
        {
            if (this.IsGoingToFloor > this.NumberFloor)
            {
                this.Position.Y -= Speed;
                this.playerInside.Position = new Vector2(this.playerInside.Position.X, this.Position.Y);
                this.playerInside.Animation.Active = false;
                if (this.Position.Y < -this.Height)
                {
                    this.HasArrived();
                }
            }
            else if (this.IsGoingToFloor < this.NumberFloor)
            {
                this.Position.Y += Speed;
                this.playerInside.Position = new Vector2(this.playerInside.Position.X, this.Position.Y);
                this.playerInside.Animation.Active = false;
                if (this.Position.Y > Client.GraphicsDevice.Viewport.Height + this.Height)
                {
                    this.HasArrived();
                }
            }
            else
            {
                this.Position.Y = Client.GraphicsDevice.Viewport.Height - this.Height;
            }
        }

        #endregion
    }
}